"""
任务管理服务
整合任务调度、执行、存储等功能
实现门面模式，提供统一的任务管理接口
"""

import asyncio
from loguru import logger
from datetime import datetime
from typing import List, Optional, Dict, Any

from app.config import settings
from app.models.task.task_data import (
    Task,
    TaskStatus,
    TaskType,
    TaskPriority,
)
from app.models.task.task_request import (
    TaskRequest,
    TaskResponse,
)

from app.core.task_scheduler.task_queue import TaskQueue
from app.core.task_scheduler.task_storage import MemoryTaskStorage
from app.core.task_scheduler.task_registry import task_registry
from app.core.sse_manager import sse_manager
from app.core.task_scheduler.executor import async_executor
from app.core.task_scheduler.executor import process_executor
from app.core.task_scheduler.task_monitor import task_monitor


class TaskManagerService:
    """任务管理服务 - 门面模式"""

    def __init__(
        self, light_workers: Optional[int] = None, heavy_workers: Optional[int] = None
    ):
        self.storage = MemoryTaskStorage()
        self.task_queue = TaskQueue(maxsize=settings.main_queue_maxsize)
        self._is_running = False
        self._worker_tasks = []
        self._shutdown_event = asyncio.Event()

        # 使用配置或默认值
        self.light_workers_count = light_workers or settings.light_workers
        self.heavy_workers_count = heavy_workers or settings.heavy_workers

        # 初始化异步队列
        self._light_queue = asyncio.Queue(maxsize=settings.light_queue_maxsize)
        self._heavy_queue = asyncio.Queue(maxsize=settings.heavy_queue_maxsize)

        # 启动执行器
        async_executor.start()
        process_executor.start()

    async def start(self):
        """启动任务管理服务"""
        if self._is_running:
            return

        self._is_running = True
        self._shutdown_event.clear()

        # 启动多个工作协程
        self._worker_tasks = []

        # 启动轻度任务工作协程
        for i in range(self.light_workers_count):
            task = asyncio.create_task(self._light_task_worker(worker_id=i))
            self._worker_tasks.append(task)

        # 启动重度任务工作协程
        for i in range(self.heavy_workers_count):
            task = asyncio.create_task(self._heavy_task_worker(worker_id=i))
            self._worker_tasks.append(task)

        # 启动任务分发协程
        dispatcher_task = asyncio.create_task(self._task_dispatcher())
        self._worker_tasks.append(dispatcher_task)

        logger.info(
            f"任务管理服务已启动 - 轻度工作协程: {self.light_workers_count}, 重度工作协程: {self.heavy_workers_count}"
        )
        await sse_manager.send_system_message(
            f"任务管理服务已启动 - 工作协程总数: {len(self._worker_tasks)}"
        )

    async def stop(self):
        """停止任务管理服务"""
        if not self._is_running:
            return

        logger.info("正在停止任务管理服务...")
        self._is_running = False
        self._shutdown_event.set()

        try:
            # 取消所有工作协程
            if self._worker_tasks:
                logger.info(f"正在取消 {len(self._worker_tasks)} 个工作协程...")
                for task in self._worker_tasks:
                    if not task.done():
                        task.cancel()

                # 等待所有协程完成，设置超时避免无限等待
                try:
                    await asyncio.wait_for(
                        asyncio.gather(*self._worker_tasks, return_exceptions=True),
                        timeout=5.0,
                    )
                    logger.info("所有工作协程已停止")
                except asyncio.TimeoutError:
                    logger.warning("工作协程停止超时，强制退出")

                self._worker_tasks.clear()

            # 清理队列
            try:
                # 清空异步队列
                while not self._light_queue.empty():
                    try:
                        self._light_queue.get_nowait()
                    except asyncio.QueueEmpty:
                        break

                while not self._heavy_queue.empty():
                    try:
                        self._heavy_queue.get_nowait()
                    except asyncio.QueueEmpty:
                        break

                # 清空主队列
                self.task_queue.clear()
                logger.info("任务队列已清理")
            except Exception as e:
                logger.error(f"清理队列时出错: {e}")

            # 关闭执行器
            try:
                await process_executor.shutdown()
                logger.info("进程执行器已关闭")
            except Exception as e:
                logger.error(f"关闭进程执行器时出错: {e}")

            try:
                async_executor.stop()
                logger.info("异步执行器已停止")
            except Exception as e:
                logger.error(f"停止异步执行器时出错: {e}")

            # 清理监控
            try:
                await task_monitor.cleanup()
                logger.info("任务监控已清理")
            except Exception as e:
                logger.error(f"清理任务监控时出错: {e}")

        except Exception as e:
            logger.error(f"停止任务管理服务时出错: {e}")
        finally:
            logger.info("任务管理服务已停止")
            await sse_manager.send_system_message("任务管理服务已停止")

    async def create_task(self, request: TaskRequest) -> TaskResponse:
        """创建任务"""
        # 验证函数是否已注册
        if not task_registry.is_registered(request.func_name):
            logger.error(f"函数 {request.func_name} 未注册")
            raise ValueError(f"函数 {request.func_name} 未注册")

        logger.info(f"函数 {request.func_name} 已注册")

        # 获取函数信息和实际函数
        task_info = task_registry.get_task_info(request.func_name)
        func = task_registry.get_function(request.func_name)

        # 确定实际任务类型
        actual_type = request.type
        if request.type == TaskType.HEAVY and asyncio.iscoroutinefunction(func):
            logger.warning(
                f"协程函数 {request.func_name} 不能作为重度任务执行，自动切换为轻度任务"
            )
            actual_type = TaskType.LIGHT

        # 创建任务实例
        task = Task(
            name=request.name,
            type=actual_type,
            func_name=request.func_name,
            args=tuple(request.args),
            kwargs=request.kwargs,
            priority=request.priority,
            timeout=request.timeout,
            max_retries=request.max_retries,
        )

        logger.info(f"创建任务: {task.name} (ID: {task.id}, 类型: {actual_type.value})")

        # 处理调度时间
        if request.schedule_time:
            # 确保schedule_time是naive datetime（不带时区信息）
            parsed_time = datetime.fromisoformat(request.schedule_time)
            if parsed_time.tzinfo is not None:
                # 如果有时区信息，转换为本地时间并移除时区信息
                task.schedule_time = parsed_time.replace(tzinfo=None)
            else:
                task.schedule_time = parsed_time

        if request.interval:
            task.interval = request.interval

        # 保存任务
        await self.storage.save_task(task)

        # 根据任务类型处理
        if task.type in [TaskType.SCHEDULED, TaskType.PERIODIC]:
            # 调度任务
            from ..core.task_scheduler.scheduler import task_scheduler

            success = await task_scheduler.schedule_task(task, self)
            if not success:
                task.status = TaskStatus.FAILED
                task.error = "调度任务失败"
                await self.storage.update_task(task)
        else:
            # 立即执行的任务加入队列
            self.task_queue.put(task)
            logger.info(f"任务已加入执行队列: {task.name}")

        # 发送任务创建通知
        await sse_manager.send_task_update(task)

        return task.to_response()

    async def _task_dispatcher(self):
        """任务分发协程 - 将任务分发到对应的队列"""
        logger.info("任务分发协程已启动")

        while self._is_running:
            try:
                # 使用异步队列获取任务
                task = await self.task_queue.async_queue.get_with_timeout(0.1)
                if task is None:
                    continue

                # 根据任务类型分发到相应队列
                if task.type == TaskType.LIGHT:
                    try:
                        await self._light_queue.put(task)
                        logger.debug(f"轻度任务已分发: {task.name}")
                    except asyncio.QueueFull:
                        logger.warning(f"轻度任务队列已满，任务 {task.name} 将被跳过")
                        # 可以考虑将任务重新放回主队列或标记为失败

                elif task.type == TaskType.HEAVY:
                    try:
                        await self._heavy_queue.put(task)
                        logger.debug(f"重度任务已分发: {task.name}")
                    except asyncio.QueueFull:
                        logger.warning(f"重度任务队列已满，任务 {task.name} 将被跳过")

            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"任务分发协程异常: {str(e)}")
                await asyncio.sleep(1)

        logger.info("任务分发协程已停止")

    async def get_task(self, task_id: str) -> Optional[TaskResponse]:
        """获取任务信息"""
        task = await self.storage.get_task(task_id)
        if not task:
            return None

        return task.to_response()

    async def list_tasks(
        self,
        status: Optional[TaskStatus] = None,
        task_type: Optional[TaskType] = None,
        limit: int = 100,
    ) -> List[TaskResponse]:
        """列出任务"""
        tasks = await self.storage.list_tasks(status, task_type, limit)

        return [task.to_response() for task in tasks]

    async def cancel_task(self, task_id: str) -> bool:
        """取消任务"""
        task = await self.storage.get_task(task_id)
        if not task:
            return False

        if task.status in [
            TaskStatus.COMPLETED,
            TaskStatus.FAILED,
            TaskStatus.CANCELLED,
        ]:
            return False

        # 如果是调度任务，取消调度
        if task.type in [TaskType.SCHEDULED, TaskType.PERIODIC]:
            from ..core.task_scheduler.scheduler import task_scheduler

            await task_scheduler.cancel_task(task_id)

        # 更新任务状态
        task.status = TaskStatus.CANCELLED
        task.completed_at = datetime.now()
        await self.storage.update_task(task)

        # 发送取消通知
        await sse_manager.send_task_update(task)
        logger.info(f"任务已取消: {task.name}")

        return True

    async def execute_task(self, task: Task) -> Task:
        """执行单个任务"""
        try:
            # 选择执行器
            if task.type == TaskType.HEAVY:
                executor = process_executor
            else:
                executor = async_executor

            # 执行任务
            result_task = await executor.run_task(task)

            # 更新存储
            await self.storage.update_task(result_task)

            return result_task

        except Exception as e:
            logger.error(f"任务执行异常: {task.name}, 错误: {str(e)}")
            task.status = TaskStatus.FAILED
            task.error = str(e)
            task.completed_at = datetime.now()
            await self.storage.update_task(task)
            return task

    async def _light_task_worker(self, worker_id: int = 0):
        """轻度任务工作协程"""
        logger.info(f"轻度任务工作协程 #{worker_id} 已启动")

        while self._is_running:
            try:
                # 从专用队列获取任务
                task = await asyncio.wait_for(self._light_queue.get(), timeout=0.1)
                if task:
                    logger.debug(f"Worker #{worker_id} 开始执行轻度任务: {task.name}")
                    await self.execute_task(task)
                    self._light_queue.task_done()

            except asyncio.TimeoutError:
                # 超时是正常的，继续循环
                continue
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"轻度任务工作协程 #{worker_id} 异常: {str(e)}")
                await asyncio.sleep(1)

        logger.info(f"轻度任务工作协程 #{worker_id} 已停止")

    async def _heavy_task_worker(self, worker_id: int = 0):
        """重度任务工作协程"""
        logger.info(f"重度任务工作协程 #{worker_id} 已启动")

        while self._is_running:
            try:
                # 从专用队列获取任务
                task = await asyncio.wait_for(self._heavy_queue.get(), timeout=0.1)
                if task:
                    logger.debug(f"Worker #{worker_id} 开始执行重度任务: {task.name}")
                    await self.execute_task(task)
                    self._heavy_queue.task_done()

            except asyncio.TimeoutError:
                # 超时是正常的，继续循环
                continue
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"重度任务工作协程 #{worker_id} 异常: {str(e)}")
                await asyncio.sleep(1)

        logger.info(f"重度任务工作协程 #{worker_id} 已停止")

    async def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        task_counts = await self.storage.get_tasks_count()
        running_tasks = await self.storage.get_running_tasks()

        return {
            "service_status": "运行中" if self._is_running else "已停止",
            "queue_size": self.task_queue.size(),
            "task_counts": {
                status.value: count for status, count in task_counts.items()
            },
            "running_tasks_count": len(running_tasks),
            "registered_functions": len(task_registry.list_registered_tasks()),
            "connected_clients": sse_manager.get_clients_count(),
            "executors": {
                "async_executor": {"running": async_executor.is_running},
                "process_executor": process_executor.get_stats(),
            },
        }

    async def cleanup(self):
        """清理已完成的任务"""
        deleted_count = await self.storage.cleanup_completed_tasks(keep_count=500)
        if deleted_count > 0:
            await sse_manager.send_system_message(
                f"已清理 {deleted_count} 个已完成的任务"
            )
        return deleted_count


# 全局任务管理服务实例
task_manager = TaskManagerService()
